package itdep.common.domain.hibernate;

import itdep.common.domain.Entity;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;

import java.util.Collection;
import java.util.Map;

/**
 * @author Ivan Khalopik
 * @version $Revision: 4 $ $Date: 2010-06-10 13:13:16 +0000 (Thu, 10 Jun 2010) $
 */
public class HibernateTemplateEx extends org.springframework.orm.hibernate3.HibernateTemplate {

	public HibernateTemplateEx() {
	}

	public HibernateTemplateEx(final SessionFactory sessionFactory) {
		super(sessionFactory);
	}

	public HibernateTemplateEx(final SessionFactory sessionFactory, final boolean allowCreate) {
		super(sessionFactory, allowCreate);
	}

	private void saveInSession(final Session session, final Object entity) {
		if (entity != null && entity instanceof Entity) {
			Entity e = (Entity) entity;
			if (e.isNew()) {
				session.save(entity);
			} else {
				session.update(entity);
			}
		} else {
			session.saveOrUpdate(entity);
		}
	}

	private void saveInSession(final Session session, final String entityName, final Object entity) {
		if (entity != null && entity instanceof Entity) {
			Entity e = (Entity) entity;
			if (e.isNew()) {
				session.save(entityName, entity);
			} else {
				session.update(entityName, entity);
			}
		} else {
			session.saveOrUpdate(entityName, entity);
		}
	}

	@Override
	public void saveOrUpdate(final Object entity) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				saveInSession(session, entity);
				return null;
			}
		});
	}

	@Override
	public void saveOrUpdate(final String entityName, final Object entity) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				saveInSession(session, entityName, entity);
				return null;
			}
		});
	}

	@Override
	public void saveOrUpdateAll(final Collection entities) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				for (final Object entity : entities) {
					saveInSession(session, entity);
				}
				return null;
			}
		});
	}

	public void saveOrUpdateAll(final String entityName, final Collection entities) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				for (final Object entity : entities) {
					saveInSession(session, entityName, entity);
				}
				return null;
			}
		});
	}

	public void saveAll(final Collection entities) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				for (final Object entity : entities) {
					session.save(entity);
				}
				return null;
			}
		});
	}

	public void saveAll(final String entityName, final Collection entities) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				for (final Object entity : entities) {
					session.save(entityName, entity);
				}
				return null;
			}
		});
	}

	public void updateAll(final Collection entities) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				for (final Object entity : entities) {
					session.update(entity);
				}
				return null;
			}
		});
	}

	public void updateAll(final String entityName, final Collection entities) throws DataAccessException {
		executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				for (final Object entity : entities) {
					session.update(entityName, entity);
				}
				return null;
			}
		});
	}

	public int executeNamedQuery(final String queryName) {
		return executeNamedQuery(queryName, null);
	}

	public int executeNamedQuery(final String queryName, final Map<String, Object> parameters) {
		return (Integer) executeWithNativeSession(new HibernateCallback<Object>() {
			public Object doInHibernate(Session session) throws HibernateException {
				Query queryObject = session.getNamedQuery(queryName);
				prepareQuery(queryObject);
				if (parameters != null) {
					for (Map.Entry<String, Object> entry : parameters.entrySet()) {
						applyNamedParameterToQuery(queryObject, entry.getKey(), entry.getValue());
					}
				}
				return queryObject.executeUpdate();
			}
		});
	}
}
